"""
企业级Loguru日志配置模块
基于loguru的企业级日志解决方案，提供结构化日志、性能监控、异常追踪等功能
"""

import os
import sys
import json
import time
from datetime import datetime
from pathlib import Path
from typing import Dict, Any, Optional, Callable
from contextvars import ContextVar

from loguru import logger
import loguru


class LoguruConfig:
    """Loguru配置管理类"""
    
    def __init__(self, 
                 environment: str = "development",
                 app_name: str = "fastapi-app",
                 log_dir: Optional[str] = None):
        self.environment = environment.lower()
        self.app_name = app_name
        self.log_dir = Path(log_dir or "./logs")
        self._ensure_log_directory()
        
        # 上下文变量，用于请求追踪
        self.request_id: ContextVar[str] = ContextVar("request_id", default="")
        self.user_id: ContextVar[str] = ContextVar("user_id", default="")
        
    def _ensure_log_directory(self) -> None:
        """确保日志目录存在"""
        self.log_dir.mkdir(parents=True, exist_ok=True)
        
        # 创建子目录
        for subdir in ["app", "access", "error", "debug", "performance"]:
            (self.log_dir / subdir).mkdir(exist_ok=True)
    
    def _get_log_file_path(self, log_type: str, rotation: str = "1 day") -> str:
        """获取日志文件路径"""
        return str(self.log_dir / log_type / f"{self.app_name}-{log_type}-{{time}}.log")
    
    def setup_logging(self) -> None:
        """设置Loguru日志配置"""
        
        # 清除默认处理器
        logger.remove()
        
        # 配置控制台输出
        self._setup_console_handler()
        
        # 配置文件输出
        self._setup_file_handlers()
        
        # 配置结构化日志
        self._setup_json_handlers()
        
        # 配置性能监控日志
        self._setup_performance_handlers()
        
        # 记录启动信息
        logger.info("Loguru日志系统已初始化", 
                   extra={"environment": self.environment, "app_name": self.app_name})
    
    def _setup_console_handler(self) -> None:
        """设置控制台处理器"""
        if self.environment == "development":
            # 开发环境：彩色控制台输出
            logger.add(
                sys.stdout,
                level="DEBUG",
                format=self._get_console_format(),
                colorize=True,
                backtrace=True,
                diagnose=True
            )
        else:
            # 生产环境：简洁控制台输出
            logger.add(
                sys.stdout,
                level="INFO",
                format=self._get_simple_format(),
                backtrace=True,
                diagnose=False
            )
    
    def _setup_file_handlers(self) -> None:
        """设置文件处理器"""
        
        # 应用日志
        logger.add(
            self._get_log_file_path("app"),
            level="INFO",
            format=self._get_structured_format(),
            rotation="1 day",
            retention="30 days",
            compression="zip",
            backtrace=True,
            diagnose=True,
            filter=self._filter_app_logs
        )
        
        # 错误日志
        logger.add(
            self._get_log_file_path("error"),
            level="ERROR",
            format=self._get_structured_format(),
            rotation="1 day",
            retention="90 days",
            compression="zip",
            backtrace=True,
            diagnose=True
        )
        
        # 调试日志（仅开发环境）
        if self.environment == "development":
            logger.add(
                self._get_log_file_path("debug"),
                level="DEBUG",
                format=self._get_structured_format(),
                rotation="1 day",
                retention="7 days",
                compression="zip",
                backtrace=True,
                diagnose=True
            )
    
    def _setup_json_handlers(self) -> None:
        """设置JSON格式处理器"""
        
        # 暂时禁用JSON格式处理器，避免兼容性问题
        # logger.add(
        #     self._get_log_file_path("app") + ".json",
        #     level="INFO",
        #     format=self._get_json_format(),
        #     rotation="1 day",
        #     retention="30 days",
        #     compression="zip",
        #     serialize=True,
        #     filter=self._filter_app_logs
        # )
        pass
    
    def _setup_performance_handlers(self) -> None:
        """设置性能监控处理器"""
        
        # 性能监控日志
        logger.add(
            self._get_log_file_path("performance"),
            level="INFO",
            format=self._get_performance_format(),
            rotation="1 day",
            retention="7 days",
            compression="zip",
            filter=self._filter_performance_logs
        )
    
    def _get_console_format(self) -> str:
        """获取控制台格式"""
        return (
            "<green>{time:YYYY-MM-DD HH:mm:ss}</green> | "
            "<level>{level: <8}</level> | "
            "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | "
            "<level>{message}</level>"
        )
    
    def _get_simple_format(self) -> str:
        """获取简单格式"""
        return "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} | {message}"
    
    def _get_structured_format(self) -> str:
        """获取结构化格式"""
        return (
            "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | "
            "{name}:{function}:{line} | {message}"
        )
    
    def _get_json_format(self) -> Callable:
        """获取JSON格式处理器"""
        def serialize(record: Dict) -> str:
            """序列化日志记录为JSON"""
            log_data = {
                "timestamp": record["time"].timestamp(),
                "level": record["level"].name,
                "logger": record["name"],
                "message": record["message"],
                "function": record["function"],
                "line": record["line"],
                "process_id": record["process"].id,
                "thread_id": record["thread"].id,
                "request_id": record["extra"].get("request_id", ""),
                "user_id": record["extra"].get("user_id", ""),
                "environment": self.environment,
                "app_name": self.app_name
            }
            
            # 添加异常信息
            if record["exception"] is not None:
                log_data["exception"] = {
                    "type": record["exception"].type.__name__,
                    "message": str(record["exception"].value),
                    "traceback": record["exception"].traceback.format()
                }
            
            # 添加自定义额外字段
            for key, value in record["extra"].items():
                if key not in ["request_id", "user_id"]:
                    log_data[key] = value
            
            return json.dumps(log_data, ensure_ascii=False, default=str) + "\n"
        
        return serialize
    
    def _get_performance_format(self) -> str:
        """获取性能监控格式"""
        return (
            "{time:YYYY-MM-DD HH:mm:ss} | PERFORMANCE | "
            "{extra[operation]} | {extra[duration_ms]:.2f}ms | "
            "{extra[resource]} | {extra[status]}"
        )
    
    def _filter_app_logs(self, record: Dict) -> bool:
        """过滤应用日志"""
        # 排除uvicorn的访问日志
        if record["name"] == "uvicorn.access":
            return False
        return True
    
    def _filter_performance_logs(self, record: Dict) -> bool:
        """过滤性能监控日志"""
        return "performance" in record["extra"]
    
    def set_request_context(self, request_id: str = "", user_id: str = "") -> None:
        """设置请求上下文"""
        self.request_id.set(request_id)
        self.user_id.set(user_id)
    
    def get_context_bindings(self) -> Dict[str, str]:
        """获取上下文绑定"""
        return {
            "request_id": self.request_id.get(),
            "user_id": self.user_id.get()
        }
    
    def bind_context(self, **kwargs) -> "loguru.Logger":
        """绑定上下文到日志记录器"""
        return logger.bind(**kwargs)


# 全局配置实例
_loguru_config: Optional[LoguruConfig] = None


def setup_loguru_logging(environment: str = None, 
                        app_name: str = "fastapi-app",
                        log_dir: str = None) -> LoguruConfig:
    """设置Loguru日志系统"""
    global _loguru_config
    
    # 从环境变量获取配置
    environment = environment or os.getenv("ENVIRONMENT", "development")
    app_name = app_name or os.getenv("APP_NAME", "fastapi-app")
    log_dir = log_dir or os.getenv("LOG_DIR", "./logs")
    
    # 创建配置实例
    _loguru_config = LoguruConfig(
        environment=environment,
        app_name=app_name,
        log_dir=log_dir
    )
    
    # 设置日志配置
    _loguru_config.setup_logging()
    
    return _loguru_config


def get_loguru_config() -> LoguruConfig:
    """获取Loguru配置实例"""
    if _loguru_config is None:
        raise RuntimeError("Loguru配置尚未初始化，请先调用setup_loguru_logging()")
    return _loguru_config


def get_logger(name: str = None) -> "loguru.Logger":
    """获取日志记录器"""
    if name:
        return logger.bind(logger=name)
    return logger


# 便捷的日志记录函数
def log_info(message: str, **kwargs):
    """记录信息日志"""
    logger.info(message, **kwargs)


def log_debug(message: str, **kwargs):
    """记录调试日志"""
    logger.debug(message, **kwargs)


def log_warning(message: str, **kwargs):
    """记录警告日志"""
    logger.warning(message, **kwargs)


def log_error(message: str, **kwargs):
    """记录错误日志"""
    logger.error(message, **kwargs)


def log_exception(message: str, exception: Exception, **kwargs):
    """记录异常日志"""
    logger.exception(f"{message}: {str(exception)}", **kwargs)


def log_performance(operation: str, duration_ms: float, resource: str = "", 
                   status: str = "success", **kwargs):
    """记录性能日志"""
    logger.info("性能监控", 
                performance=True,
                operation=operation,
                duration_ms=duration_ms,
                resource=resource,
                status=status,
                **kwargs)


# 日志装饰器
def log_execution_time(func_name: str = None):
    """记录函数执行时间的装饰器"""
    def decorator(func):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            operation_name = func_name or func.__name__
            
            try:
                result = func(*args, **kwargs)
                duration_ms = (time.time() - start_time) * 1000
                
                log_performance(
                    operation=operation_name,
                    duration_ms=duration_ms,
                    resource=f"{func.__module__}.{func.__name__}",
                    status="success"
                )
                
                return result
            except Exception as e:
                duration_ms = (time.time() - start_time) * 1000
                
                log_performance(
                    operation=operation_name,
                    duration_ms=duration_ms,
                    resource=f"{func.__module__}.{func.__name__}",
                    status="error"
                )
                
                log_exception(f"函数 {operation_name} 执行异常", e)
                raise
        
        return wrapper
    return decorator


def log_api_call(endpoint: str, method: str):
    """记录API调用日志的装饰器"""
    def decorator(func):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            
            try:
                result = func(*args, **kwargs)
                duration_ms = (time.time() - start_time) * 1000
                
                log_info(
                    f"API调用: {method} {endpoint}",
                    endpoint=endpoint,
                    method=method,
                    duration_ms=duration_ms,
                    status="success"
                )
                
                return result
            except Exception as e:
                duration_ms = (time.time() - start_time) * 1000
                
                log_error(
                    f"API调用异常: {method} {endpoint}",
                    endpoint=endpoint,
                    method=method,
                    duration_ms=duration_ms,
                    status="error",
                    error=str(e)
                )
                raise
        
        return wrapper
    return decorator


if __name__ == "__main__":
    # 测试Loguru配置
    config = setup_loguru_logging(environment="development", app_name="test-app")
    
    # 测试不同级别的日志
    log_debug("这是调试信息")
    log_info("应用启动成功")
    log_warning("这是警告信息")
    log_error("这是错误信息")
    
    # 测试上下文绑定
    config.set_request_context(request_id="test-123", user_id="user-456")
    
    # 测试结构化日志
    log_info("用户登录", 
             user_id="12345", 
             ip_address="192.168.1.100",
             user_agent="Mozilla/5.0")
    
    # 测试性能日志
    log_performance("数据库查询", 152.34, "users_table", "success")
    
    # 测试异常日志
    try:
        1 / 0
    except Exception as e:
        log_exception("除零错误", e)
    
    print("Loguru日志测试完成，请检查logs目录中的日志文件")